#include <termios.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <termios.h>
#include <stdlib.h>
#include <string.h>
#include <wctype.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <wchar.h>
#include <errno.h>
#include <unistd.h>

#include "config.h"

#if defined(HAVE_CURSES_H)
#include <curses.h>
#elif defined(HAVE_NCURSES_H)
#include <ncurses.h>
#elif defined(HAVE_NCURSES_NCURSES_H)
#include <ncurses/ncurses.h>
#endif

#if defined(__CYGWIN__)
#include <ncurses/term.h>
#include <sys/time.h>
#endif

#include "pipes/pipes.h"

enum eTerminalKanjiCode gTerminalKanjiCode = kTKUtf8;

#define TERM_SIZE_MAX 512
#define UTF_CHAR_SIZE_MAX 6

static char gBuf[TERM_SIZE_MAX][TERM_SIZE_MAX];
static char gBufBfr[TERM_SIZE_MAX][TERM_SIZE_MAX];
static wchar_t gWBuf[TERM_SIZE_MAX][TERM_SIZE_MAX];
static wchar_t gWBufBfr[TERM_SIZE_MAX][TERM_SIZE_MAX];
static int gBufAttr[TERM_SIZE_MAX][TERM_SIZE_MAX];
static int gBufAttrBfr[TERM_SIZE_MAX][TERM_SIZE_MAX];
static int gBufAttrNow = 0;
static char* gBuffer;
static int gBufferSize = 512*128;
static char* gBufferPtr;

static int gX = 0, gY = 0;
int gKeyEscapeWait = 150000;

struct sKeyMap
{
    int mKey;
    unsigned char mKeys[kKeyMapKeysMax];
    int mNum;
};

static struct sKeyMap* gKeyMap;
static int gKeyMapSize;
static int gKeyMapNum;

static int wis_2cols(wchar_t c)
{
    wchar_t buf[256];

    buf[0] = c;
    buf[1] = 0;

    return wcswidth(buf, 10) == 2;
}

int gMCTtyFd;

static int ttywrite(char* str)
{
    return write(gMCTtyFd, str, strlen(str));
}

static int ttywritec(char c)
{
    return write(gMCTtyFd, &c, 1);
}

static size_t ttyread(void *buf, size_t nbytes)
{
    return read(gMCTtyFd, buf, nbytes);
}

//////////////////////////////////////////////////////////////////////
// is hankaku character
//////////////////////////////////////////////////////////////////////
static int mhas_color()
{
    return tigetstr("setaf") == NULL;
}

void mbackspace_immediately()
{
    ttywrite(tigetstr("cub1"));
    ttywrite(tigetstr("dch1"));
}

void mbackspace_head_of_line_immediately()
{
    const int maxx = mgetmaxx();

    ttywrite(tigetstr("cuu1"));
    ttywrite(tparm(tigetstr("cuf"), maxx));
    ttywrite(tigetstr("dch1"));
}

void mcursor_left_immediately(int n)
{
    ttywrite(tparm(tigetstr("cub"), n));
}

void mcursor_right_immediately(int n)
{
    ttywrite(tparm(tigetstr("cuf"), n));
}


void mmove_line_home_immediately()
{
    const int maxx = mgetmaxx();

    ttywrite(tparm(tigetstr("cub"), maxx));
}
/*
static char gKeyRing[128];
static char* gKeyRingHead;
static char* gKeyRingTail;
*/

void mcurses_init(enum eTerminalKanjiCode code)
{
    if(setupterm(NULL, STDOUT_FILENO, (int*) 0) == ERR) {
        fprintf(stderr, "invalid TERM setting");
        exit(1);
    }

    gMCTtyFd = open("/dev/tty", O_RDWR);
    signed char keymaps[][kKeyMapKeysMax] = {
        {27,   '[',   'A',   -1,   -1,  -1, -1,-1,-1,-1},   // KEY_UP
        {27,   '[',   'B',   -1,   -1,  -1, -1,-1,-1,-1},   // KYE_DOWN
        {27,   '[',   'C',   -1,   -1,  -1, -1,-1,-1,-1},   // KEY_RIGHT
        {27,   '[',   'D',   -1,   -1,  -1, -1,-1,-1,-1},   // KEY_LEFT
        {27,   '[',   '2',  '~',  -1,  -1, -1,-1,-1,-1},   // KEY_IC
        {27,   91,    51,   126,   -1,  -1, -1,-1,-1,-1},   // KEY_DC
        {27,   'O',   'H',   -1,   -1,  -1, -1,-1,-1,-1},   // KEY_HOME
        {27,   'O',   'F',   -1,   -1,  -1, -1,-1,-1,-1},   // KEY_END
        {27,   '[',   '5',  '~',  -1,  -1, -1,-1,-1,-1},   // KEY_PPAGE PageUp
        {27,   '[',   '6',  '~',  -1,  -1, -1,-1,-1,-1},   // KEY_NPAGE PageDown
        {27,   '[',   '1',  '1', '~', -1, -1,-1,-1,-1},   // F1
        {27,   '[',   '1',  '2', '~', -1, -1,-1,-1,-1},   // F2
        {27,   '[',   '1',  '3', '~', -1, -1,-1,-1,-1},   // F3
        {27,   '[',   '1',  '4', '~', -1, -1,-1,-1,-1},   // F4
        {27,   '[',   '1',  '5', '~', -1, -1,-1,-1,-1},   // F5
        {27,   '[',   '1',  '7', '~', -1, -1,-1,-1,-1},   // F6
        {27,   '[',   '1',  '8', '~', -1, -1,-1,-1,-1},   // F7
        {27,   '[',   '1',  '9', '~', -1, -1,-1,-1,-1},   // F8
        {27,   '[',   '2',  '0', '~', -1, -1,-1,-1,-1},   // F9
        {27,   '[',   '2',  '1', '~', -1, -1,-1,-1,-1},   // F1-1
        {27,   '[',   '2',  '3', '~', -1, -1,-1,-1,-1},   // F11
        {27,   '[',   '2',  '4', '~', -1, -1,-1,-1,-1},    // F12
        {27,   'O',   'A',   -1,   -1,  -1, -1,-1,-1,-1},   // KEY_UP
        {27,   'O',   'B',   -1,   -1,  -1, -1,-1,-1,-1},   // KYE_DOWN
        {27,   'O',   'C',   -1,   -1,  -1, -1,-1,-1,-1},   // KEY_RIGHT
        {27,   'O',   'D',   -1,   -1,  -1, -1,-1,-1,-1},   // KEY_LEFT
        {127,   -1,    -1,   -1,   -1,  -1, -1,-1,-1,-1},    // KEY_BACKSPACE
    };

    gKeyMapSize = 32;
    gKeyMap = MALLOC(sizeof(struct sKeyMap)*gKeyMapSize);
    gKeyMapNum = 0;

    madd_keymap(KEY_UP, keymaps[0]);
    madd_keymap(KEY_DOWN, keymaps[1]);
    madd_keymap(KEY_RIGHT, keymaps[2]);
    madd_keymap(KEY_LEFT, keymaps[3]);
    madd_keymap(KEY_IC, keymaps[4]);
    madd_keymap(KEY_DC, keymaps[5]);
    madd_keymap(KEY_HOME, keymaps[6]);
    madd_keymap(KEY_END, keymaps[7]);
    madd_keymap(KEY_PPAGE, keymaps[8]);
    madd_keymap(KEY_NPAGE, keymaps[9]);
    madd_keymap(KEY_F(1), keymaps[10]);
    madd_keymap(KEY_F(2), keymaps[11]);
    madd_keymap(KEY_F(3), keymaps[12]);
    madd_keymap(KEY_F(4), keymaps[13]);
    madd_keymap(KEY_F(5), keymaps[14]);
    madd_keymap(KEY_F(6), keymaps[15]);
    madd_keymap(KEY_F(7), keymaps[16]);
    madd_keymap(KEY_F(8), keymaps[17]);
    madd_keymap(KEY_F(9), keymaps[18]);
    madd_keymap(KEY_F(10), keymaps[19]);
    madd_keymap(KEY_F(11), keymaps[20]);
    madd_keymap(KEY_F(12), keymaps[21]);
    madd_keymap(KEY_UP, keymaps[22]);
    madd_keymap(KEY_DOWN, keymaps[23]);
    madd_keymap(KEY_RIGHT, keymaps[24]);
    madd_keymap(KEY_LEFT, keymaps[25]);
    madd_keymap(KEY_BACKSPACE, keymaps[26]);

    gTerminalKanjiCode = code;
    gBufferSize = 512*128;
    gBuffer = MALLOC(gBufferSize);;
/*
    memset(gKeyRing, 0, 128);
    gKeyRingHead = gKeyRing;
    gKeyRingTail = gKeyRing;
*/
}

void mcurses_final()
{
    FREE(gKeyMap);

    FREE(gBuffer);

    close(gMCTtyFd);
    
    //mreset_tty();
}

struct termios gSaveTty;

void msave_ttysettings()
{
    tcgetattr(gMCTtyFd, &gSaveTty);
}

void mrestore_ttysettings()
{
    tcsetattr(gMCTtyFd, TCSANOW, &gSaveTty);
}

void minitscr()
{
    struct termios t;
    int x,y;
    int i, j;
    struct sKeyMap* item;

    tcgetattr(STDIN_FILENO, &t);

    t.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE);

# if defined(IEXTEN) && !defined(__MINT__)
    t.c_lflag &= ~IEXTEN;
# endif

/*
# ifdef ONLCR
   t.c_oflag &= ~ONLCR;
# endif
    t.c_iflag &= ~ICRNL;
*/

/*
#ifdef ECHOPRT
    t.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOCTL | ECHOE| ECHOK | ECHOKE
                         | ECHONL | ECHOPRT);
#else
    t.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE
                  | ECHONL);
#endif
*/
    t.c_iflag |= IGNBRK;
    t.c_iflag &= ~(IXOFF|IXON);

    t.c_cc[VMIN] = 0;
    t.c_cc[VTIME] = 0;
    t.c_cc[VLNEXT] = 0;
    t.c_cc[VDISCARD] = 0;

    tcsetattr(STDIN_FILENO, TCSANOW, &t);

    if(gTerminalKanjiCode == kTKUtf8) {
        for(x=0; x<TERM_SIZE_MAX; x++) {
            for(y=0; y<TERM_SIZE_MAX; y++) {
                gWBufBfr[y][x] = 0;
                gBufAttrBfr[y][x] = 0;
            }
        }
    }
    else {
        for(x=0; x<TERM_SIZE_MAX; x++) {
            for(y=0; y<TERM_SIZE_MAX; y++) {
                gBufBfr[y][x] = 0;
                gBufAttrBfr[y][x] = 0;
            }
        }
    }


    mclear();

    gBufAttrNow = 0;
}




void mendwin()
{
/*
    mmove_immediately(0, 0);
    mclear_immediately();
    mrefresh();
*/
}

void madd_keymap(int key, signed char keys[kKeyMapKeysMax])
{
    int i;
    
    if(gKeyMapNum >= gKeyMapSize) {
        int new_size = gKeyMapSize * 1.8;
        gKeyMap = REALLOC(gKeyMap, sizeof(struct sKeyMap)*new_size);
        memset(gKeyMap + gKeyMapSize, 0, sizeof(struct sKeyMap)*(new_size - gKeyMapSize));
        gKeyMapSize = new_size;
    }
    struct sKeyMap* keymap = gKeyMap + gKeyMapNum;
    gKeyMapNum++;

    keymap->mKey = key;
    keymap->mNum = -1;
    for(i=0; i<kKeyMapKeysMax; i++) {
        keymap->mKeys[i] = keys[i];

        if(keys[i] == -1 && keymap->mNum == -1) {
            keymap->mNum = i;
        }
    }
}




void mclear()
{
    char space[1024];
    char space2[1024];
    int x, y;
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();


    for(x=0; x<maxx; x++) {
       space[x] = ' ';
    }
    space[x] = 0;

#if defined(__CYGWIN__)
    for(x=0; x<maxx-1; x++) {
       space2[x] = ' ';
    }
    space2[x] = 0;

    mattron(0);
    for(y=0; y<maxy-1; y++) {
       mmvprintw(y, 0, space);
    }
    mmvprintw(maxy-1, 0, space2);
#else
    mattron(0);
    for(y=0; y<maxy; y++) {
       mmvprintw(y, 0, space);
    }
#endif

    gX = 0;
    gY = 0;
}

void mclear_immediately()
{
    mclear();
    mrefresh();

    ttywrite(tigetstr("clear"));
}

void mclear_online(int y)
{
    char space[1024];
    int x;

    const int maxx = mgetmaxx();

#if defined(__CYGWIN__)
    const int maxy = mgetmaxy();

    if(y == maxy-1) {
        for(x=0; x<maxx-1; x++) {
            space[x] = ' ';
        }
    }
    else {
        for(x=0; x<maxx; x++) {
            space[x] = ' ';
        }
    }
#else
    for(x=0; x<maxx; x++) {
        space[x] = ' ';
    }
#endif
    space[x] = 0;

    mattron(0);
    mmvprintw(y, 0, space);
}




void mmove(int y, int x)
{
    gX = x;
    gY = y;
}




void mmove_immediately(int y, int x)
{
    ttywrite(tparm(tigetstr("cup"), y, x));
}

int mmvprintw_immediately(int y, int x, char* str, ...)
{
    char buf[BUFSIZ];
    int i;

    va_list args;
    va_start(args, str);
    i = vsnprintf(buf, BUFSIZ, str, args);
    va_end(args);

    mmove_immediately(y, x);

    ttywrite(buf);

    return i;
}

int mprintw_immediately(char* str, ...)
{
    char buf[BUFSIZ];
    int i;

    va_list args;
    va_start(args, str);
    i = vsnprintf(buf, BUFSIZ, str, args);
    va_end(args);

    ttywrite(buf);

    return i;
}

int mmvprintw(int y, int x, char* str, ...)
{
    char buf[BUFSIZ];
    int i;
    char* p;
    wchar_t wbuf[BUFSIZ];
    wchar_t* wp;

    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    va_list args;
    va_start(args, str);
    i = vsnprintf(buf, BUFSIZ, str, args);
    va_end(args);

    mmove(y, x);

    if(gTerminalKanjiCode == kTKUtf8) {
        if(mbstowcs(wbuf, buf, BUFSIZ) == -1) {
            mbstowcs(wbuf, "?????", BUFSIZ);
        }

        wp = wbuf;
        while(*wp) {
            if(wis_2cols(*wp)) {
                gWBuf[gY][gX] = *wp;
                gWBuf[gY][gX+1] = 0;
                gBufAttr[gY][gX] = gBufAttrNow;
                gBufAttr[gY][gX+1] = 0;
                gX+=2;

                if(gX >= maxx) {
                    gX = 0;
                    gY++;
                }
                wp++;
            }
            else if(*wp == '\t') {
                gWBuf[gY][gX] = ' ';
                gBufAttr[gY][gX] = gBufAttrNow;
                gX++;

                if(gX >= maxx) {
                    gX = 0;
                    gY++;
                }
                wp++;
            }
            else if(*wp == '\n') {
                gY++;
                gX = 0;
                wp++;
                if(gY >= maxy) {
                    gY = maxy-1;;
                }
            }
            else {
                gWBuf[gY][gX] = *wp;
                gBufAttr[gY][gX] = gBufAttrNow;
                gX++;

                if(gX >= maxx) {
                    gX = 0;
                    gY++;
                }
                wp++;
            }
        }
    }
    else {
        p = buf;
        while(*p) {
            if(*p == '\n') {
                gX = 0;
                gY++;
                p++;
                if(gY >= maxy) {
                    gY = maxy-1;;
                }
            }
            else if(*p == '\t') {
                gBuf[gY][gX] = ' ';
                gBufAttr[gY][gX] = gBufAttrNow;
                gX++;
                if(gX >= maxx) {
                    gX = 0;
                    gY++;
                }
                p++;
            }
            else {
                gBuf[gY][gX] = *p;
                gBufAttr[gY][gX] = gBufAttrNow;
                gX++;
                if(gX >= maxx) {
                    gX = 0;
                    gY++;
                }
                p++;
            }
        }
    }

    return i;
}




int mprintw(char* str, ...)
{
    char buf[BUFSIZ];
    wchar_t wbuf[BUFSIZ];
    wchar_t* wp;
    int i;
    char* p;

    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    va_list args;
    va_start(args, str);
    i = vsnprintf(buf, BUFSIZ, str, args);
    va_end(args);

    if(gTerminalKanjiCode == kTKUtf8) {
        if(mbstowcs(wbuf, buf, BUFSIZ) == -1) {
            mbstowcs(wbuf, "?????", BUFSIZ);
        }

        wp = wbuf;
        while(*wp) {
            if(wis_2cols(*wp)) {
                gWBuf[gY][gX] = *wp;
                gWBuf[gY][gX+1] = 0;
                gBufAttr[gY][gX] = gBufAttrNow;
                gBufAttr[gY][gX+1] = 0;
                gX+=2;

                if(gX >= maxx) {
                    gX = 0;
                    gY++;
                }
                wp++;
            }
            else if(*wp == '\n') {
                gY++;
                gX = 0;
                wp++;
                if(gY >= maxy) {
                    gY = maxy-1;;
                }
            }
            else if(*wp == '\t') {
                gWBuf[gY][gX] = ' ';
                gBufAttr[gY][gX] = gBufAttrNow;
                gX++;

                if(gX >= maxx) {
                    gX = 0;
                    gY++;
                }
                wp++;
            }
            else {
                gWBuf[gY][gX] = *wp;
                gBufAttr[gY][gX] = gBufAttrNow;
                gX++;

                if(gX >= maxx) {
                    gX = 0;
                    gY++;
                }
                wp++;
            }
        }
    }
    else {
        p = buf;
        while(*p) {
            if(*p == '\n') {
                gY++;
                gX = 0;
                p++;
                if(gY >= maxy) {
                    gY = maxy-1;;
                }
            }
            else if(*p == '\t') {
                gBuf[gY][gX] = ' ';
                gBufAttr[gY][gX] = gBufAttrNow;
                gX++;
                if(gX >= maxx) {
                    gX = 0;
                    gY++;
                }
                p++;
            }
            else {
                gBuf[gY][gX] = *p;
                gBufAttr[gY][gX] = gBufAttrNow;
                gX++;
                if(gX >= maxx) {
                    gX = 0;
                    gY++;
                }
                p++;
            }
        }
    }

    return i;
}




void mattron(int attrs)
{
    gBufAttrNow = attrs;
}




void mattroff()
{
    gBufAttrNow = 0;
}




void mbox(int y, int x, int width, int height)
{
   char hbar[256];
   int i;

   hbar[0] = '+';
   for(i=1; i<width-1; i++) {
      hbar[i] = '-';
   }
   hbar[i] = '+';
   hbar[i+1] = 0;

   mmvprintw(y, x, hbar);
   for(i=0; i<height-2; i++) {
       char hbar2[256];

       int j;
       hbar2[0] = '|';
       for(j=1; j<width-1; j++) {
           hbar2[j] = ' ';
       }
       hbar2[j] = '|';
       hbar2[j+1] = 0;

       mmvprintw(y + 1 +i, x, hbar2);

/*
       mmvprintw(y + 1 + i, x, "|");
       mmvprintw(y + 1 + i, x + width-1, "|");
*/
   }

   mmvprintw(y + height-1, x, hbar);
}

static void ttywrite_to_buffer(char* buf)
{
    char* p = buf;
    while(*p) {
        if(gBufferPtr - gBuffer >= gBufferSize) {
            gBufferSize *= 2;
            int len = gBufferPtr - gBuffer;
            gBuffer = REALLOC(gBuffer, gBufferSize);
            gBufferPtr = gBuffer + len;
         }
        *gBufferPtr++ = *p++;
    }
}

static void ttywrite_to_bufferc(char c)
{
    if(gBufferPtr - gBuffer >= gBufferSize) {
        gBufferSize *= 2;
        int len = gBufferPtr - gBuffer;
        gBuffer = REALLOC(gBuffer, gBufferSize);
        gBufferPtr = gBuffer + len;
    }
    *gBufferPtr++ = c;
}

static void buffer_to_tty()
{
    *gBufferPtr = 0;

    char buf[BUFSIZ+1];
    char* p = gBuffer;
    while(1) {
        if(gBufferPtr - p > BUFSIZ) {
            memcpy(buf, p, BUFSIZ);
            buf[BUFSIZ] = 0;
            ttywrite(buf);
            p+=BUFSIZ;
        }
        else {
            ttywrite(p);
            break;
        }
    }
}

static void mrefresh_buffer()
{
    int x, y;
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();
    char* p;
    char mbs[256];
    wchar_t wcs[256];

    gBufferPtr = gBuffer;

    if(gTerminalKanjiCode == kTKUtf8) {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                if(gWBuf[y][x] != gWBufBfr[y][x]
                    || gBufAttr[y][x] != gBufAttrBfr[y][x]

                    || (wis_2cols(gWBuf[y][x])
                        && (gWBuf[y][x] != gWBufBfr[y][x]
                            || gBufAttr[y][x] != gBufAttrBfr[y][x]
                            || gWBuf[y][x+1] != gWBufBfr[y][x+1]
                            || gBufAttr[y][x+1] != gBufAttrBfr[y][x+1]
                            )))
                {
                    ttywrite_to_buffer(tparm(tigetstr("cup"), y, x));

                    if(gBufAttr[y][x] & kCAReverse) ttywrite_to_buffer(tigetstr("rev"));
                    if(gBufAttr[y][x] & kCABold) ttywrite_to_buffer(tigetstr("bold"));
                    if(gBufAttr[y][x] & kCAUnderline) ttywrite_to_buffer(tigetstr("rmul"));
                    if(gBufAttr[y][x] & kCABlack) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 0, 0));
                    }
                    if(gBufAttr[y][x] & kCARed) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 1, 0));
                    }
                    if(gBufAttr[y][x] & kCAGreen) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 2, 0));
                    }
                    if(gBufAttr[y][x] & kCAYellow) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 3, 0));
                    }
                    if(gBufAttr[y][x] & kCABlue) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 4, 0));
                    }
                    if(gBufAttr[y][x] & kCAMagenta) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 5, 0));
                    }
                    if(gBufAttr[y][x] & kCACyan) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 6, 0));
                    }
                    if(gBufAttr[y][x] & kCAWhite) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 7, 0));
                    }
                    if(gBufAttr[y][x] & kCABackBlack) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 0, 0));
                    }
                    if(gBufAttr[y][x] & kCABackRed) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 1, 0));
                    }
                    if(gBufAttr[y][x] & kCABackGreen) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 2, 0));
                    }
                    if(gBufAttr[y][x] & kCABackYellow) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 3, 0));
                    }
                    if(gBufAttr[y][x] & kCABackBlue) {
                        p = tigetstr("setab");
                            if(p) ttywrite_to_buffer(tparm(p, 4, 0));
                    }
                    if(gBufAttr[y][x] & kCABackMagenta) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 5, 0));
                    }
                    if(gBufAttr[y][x] & kCABackCyan) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 6, 0));
                    }
                    if(gBufAttr[y][x] & kCABackWhite) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 7, 0));
                    }

                    wcs[0] = gWBuf[y][x];
                    wcs[1] = 0;
                    wcstombs(mbs, wcs, 256);
                    ttywrite_to_buffer(mbs);

                    if(gBufAttr[y][x]) ttywrite_to_buffer(tigetstr("sgr0"));
                }

                if(wis_2cols(gWBuf[y][x])) {
                    x++;
                }
            }
        }
    }
    else {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                if(gBuf[y][x] !=0
                    && (
                        gBuf[y][x] != gBufBfr[y][x]
                        || gBufAttr[y][x] != gBufAttrBfr[y][x]

                    || (is_kanji(gTerminalKanjiCode, gBuf[y][x])
                        && (gBuf[y][x] != gBufBfr[y][x]
                            || gBufAttr[y][x] != gBufAttrBfr[y][x]
                            || gBuf[y][x+1] != gBufBfr[y][x+1]
                            || gBufAttr[y][x+1] != gBufAttrBfr[y][x+1]
                            ))))
                {
                    ttywrite_to_buffer(tparm(tigetstr("cup"), y, x));

                    if(gBufAttr[y][x] & kCAReverse) ttywrite_to_buffer(tigetstr("rev"));
                    if(gBufAttr[y][x] & kCABold) ttywrite_to_buffer(tigetstr("bold"));
                    if(gBufAttr[y][x] & kCAUnderline) ttywrite_to_buffer(tigetstr("rmul"));
                    if(gBufAttr[y][x] & kCABlack) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 0, 0));
                    }
                    if(gBufAttr[y][x] & kCARed) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 1, 0));
                    }
                    if(gBufAttr[y][x] & kCAGreen) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 2, 0));
                    }
                    if(gBufAttr[y][x] & kCAYellow) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 3, 0));
                    }
                    if(gBufAttr[y][x] & kCABlue) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 4, 0));
                    }
                    if(gBufAttr[y][x] & kCAMagenta) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 5, 0));
                    }
                    if(gBufAttr[y][x] & kCACyan) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 6, 0));
                    }
                    if(gBufAttr[y][x] & kCAWhite) {
                        p = tigetstr("setaf");
                        if(p) ttywrite_to_buffer(tparm(p, 7, 0));
                    }
                    if(gBufAttr[y][x] & kCABackBlack) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 0, 0));
                    }
                    if(gBufAttr[y][x] & kCABackRed) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 1, 0));
                    }
                    if(gBufAttr[y][x] & kCABackGreen) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 2, 0));
                    }
                    if(gBufAttr[y][x] & kCABackYellow) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 3, 0));
                    }
                    if(gBufAttr[y][x] & kCABackBlue) {
                        p = tigetstr("setab");
                            if(p) ttywrite_to_buffer(tparm(p, 4, 0));
                    }
                    if(gBufAttr[y][x] & kCABackMagenta) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 5, 0));
                    }
                    if(gBufAttr[y][x] & kCABackCyan) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 6, 0));
                    }
                    if(gBufAttr[y][x] & kCABackWhite) {
                        p = tigetstr("setab");
                        if(p) ttywrite_to_buffer(tparm(p, 7, 0));
                    }

                    if(is_kanji(gTerminalKanjiCode, gBuf[y][x]) 
                        && !is_hankaku(gTerminalKanjiCode, gBuf[y][x])) 
                    {
                        ttywrite_to_bufferc(gBuf[y][x]);
                        ttywrite_to_bufferc(gBuf[y][x+1]);
                    }
                    else if(is_kanji(gTerminalKanjiCode, gBuf[y][x]) 
                        && is_hankaku(gTerminalKanjiCode, gBuf[y][x])) 
                    {
                        ttywrite_to_bufferc(gBuf[y][x]);
                        ttywrite_to_bufferc(gBuf[y][x+1]);
                        ttywrite_to_bufferc(' ');
                    }
                    else {
                        ttywrite_to_bufferc(gBuf[y][x]);
                    }

                    if(gBufAttr[y][x]) ttywrite_to_buffer(tigetstr("sgr0"));
                }

                if(is_kanji(gTerminalKanjiCode, gBuf[y][x])) {
                    x++;
                }
            }
        }
    }

    ttywrite_to_buffer(tparm(tigetstr("cup"), gY, gX));
    buffer_to_tty();

    if(gTerminalKanjiCode == kTKUtf8) {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                gWBufBfr[y][x] = gWBuf[y][x];
                gBufAttrBfr[y][x] = gBufAttr[y][x];
            }
        }
    }
    else {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                gBufBfr[y][x] = gBuf[y][x];
                gBufAttrBfr[y][x] = gBufAttr[y][x];
            }
        }
    }
}

static void mrefresh_non_buffer()
{
    int x, y;
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();
    char* p;
    char mbs[256];
    wchar_t wcs[256];

    if(gTerminalKanjiCode == kTKUtf8) {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                if(gWBuf[y][x] != gWBufBfr[y][x]
                    || gBufAttr[y][x] != gBufAttrBfr[y][x]

                    || (wis_2cols(gWBuf[y][x])
                        && (gWBuf[y][x] != gWBufBfr[y][x]
                            || gBufAttr[y][x] != gBufAttrBfr[y][x]
                            || gWBuf[y][x+1] != gWBufBfr[y][x+1]
                            || gBufAttr[y][x+1] != gBufAttrBfr[y][x+1]
                            )))
                {
                    ttywrite(tparm(tigetstr("cup"), y, x));

                    if(gBufAttr[y][x] & kCAReverse) ttywrite(tigetstr("rev"));
                    if(gBufAttr[y][x] & kCABold) ttywrite(tigetstr("bold"));
                    if(gBufAttr[y][x] & kCAUnderline) ttywrite(tigetstr("rmul"));
                    if(gBufAttr[y][x] & kCABlack) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 0, 0));
                    }
                    if(gBufAttr[y][x] & kCARed) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 1, 0));
                    }
                    if(gBufAttr[y][x] & kCAGreen) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 2, 0));
                    }
                    if(gBufAttr[y][x] & kCAYellow) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 3, 0));
                    }
                    if(gBufAttr[y][x] & kCABlue) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 4, 0));
                    }
                    if(gBufAttr[y][x] & kCAMagenta) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 5, 0));
                    }
                    if(gBufAttr[y][x] & kCACyan) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 6, 0));
                    }
                    if(gBufAttr[y][x] & kCAWhite) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 7, 0));
                    }
                    if(gBufAttr[y][x] & kCABackBlack) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 0, 0));
                    }
                    if(gBufAttr[y][x] & kCABackRed) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 1, 0));
                    }
                    if(gBufAttr[y][x] & kCABackGreen) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 2, 0));
                    }
                    if(gBufAttr[y][x] & kCABackYellow) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 3, 0));
                    }
                    if(gBufAttr[y][x] & kCABackBlue) {
                        p = tigetstr("setab");
                            if(p) ttywrite(tparm(p, 4, 0));
                    }
                    if(gBufAttr[y][x] & kCABackMagenta) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 5, 0));
                    }
                    if(gBufAttr[y][x] & kCABackCyan) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 6, 0));
                    }
                    if(gBufAttr[y][x] & kCABackWhite) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 7, 0));
                    }

                    wcs[0] = gWBuf[y][x];
                    wcs[1] = 0;
                    wcstombs(mbs, wcs, 256);
                    ttywrite(mbs);

                    if(gBufAttr[y][x]) ttywrite(tigetstr("sgr0"));
                }

                if(wis_2cols(gWBuf[y][x])) {
                    x++;
                }
            }
        }
    }
    else {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                if(gBuf[y][x] !=0
                    && (
                        gBuf[y][x] != gBufBfr[y][x]
                        || gBufAttr[y][x] != gBufAttrBfr[y][x]

                    || (is_kanji(gTerminalKanjiCode, gBuf[y][x])
                        && (gBuf[y][x] != gBufBfr[y][x]
                            || gBufAttr[y][x] != gBufAttrBfr[y][x]
                            || gBuf[y][x+1] != gBufBfr[y][x+1]
                            || gBufAttr[y][x+1] != gBufAttrBfr[y][x+1]
                            ))))
                {
                    ttywrite(tparm(tigetstr("cup"), y, x));

                    if(gBufAttr[y][x] & kCAReverse) ttywrite(tigetstr("rev"));
                    if(gBufAttr[y][x] & kCABold) ttywrite(tigetstr("bold"));
                    if(gBufAttr[y][x] & kCAUnderline) ttywrite(tigetstr("rmul"));
                    if(gBufAttr[y][x] & kCABlack) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 0, 0));
                    }
                    if(gBufAttr[y][x] & kCARed) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 1, 0));
                    }
                    if(gBufAttr[y][x] & kCAGreen) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 2, 0));
                    }
                    if(gBufAttr[y][x] & kCAYellow) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 3, 0));
                    }
                    if(gBufAttr[y][x] & kCABlue) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 4, 0));
                    }
                    if(gBufAttr[y][x] & kCAMagenta) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 5, 0));
                    }
                    if(gBufAttr[y][x] & kCACyan) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 6, 0));
                    }
                    if(gBufAttr[y][x] & kCAWhite) {
                        p = tigetstr("setaf");
                        if(p) ttywrite(tparm(p, 7, 0));
                    }
                    if(gBufAttr[y][x] & kCABackBlack) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 0, 0));
                    }
                    if(gBufAttr[y][x] & kCABackRed) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 1, 0));
                    }
                    if(gBufAttr[y][x] & kCABackGreen) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 2, 0));
                    }
                    if(gBufAttr[y][x] & kCABackYellow) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 3, 0));
                    }
                    if(gBufAttr[y][x] & kCABackBlue) {
                        p = tigetstr("setab");
                            if(p) ttywrite(tparm(p, 4, 0));
                    }
                    if(gBufAttr[y][x] & kCABackMagenta) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 5, 0));
                    }
                    if(gBufAttr[y][x] & kCABackCyan) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 6, 0));
                    }
                    if(gBufAttr[y][x] & kCABackWhite) {
                        p = tigetstr("setab");
                        if(p) ttywrite(tparm(p, 7, 0));
                    }

                    if(is_kanji(gTerminalKanjiCode, gBuf[y][x]) 
                        && !is_hankaku(gTerminalKanjiCode, gBuf[y][x])) 
                    {
                        ttywritec(gBuf[y][x]);
                        ttywritec(gBuf[y][x+1]);
                    }
                    else if(is_kanji(gTerminalKanjiCode, gBuf[y][x]) 
                        && is_hankaku(gTerminalKanjiCode, gBuf[y][x])) 
                    {
                        ttywritec(gBuf[y][x]);
                        ttywritec(gBuf[y][x+1]);
                        ttywritec(' ');
                    }
                    else {
                        ttywritec(gBuf[y][x]);
                    }

                    if(gBufAttr[y][x]) ttywrite(tigetstr("sgr0"));
                }

                if(is_kanji(gTerminalKanjiCode, gBuf[y][x])) {
                    x++;
                }
            }
        }
    }

    ttywrite(tparm(tigetstr("cup"), gY, gX));

    if(gTerminalKanjiCode == kTKUtf8) {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                gWBufBfr[y][x] = gWBuf[y][x];
                gBufAttrBfr[y][x] = gBufAttr[y][x];
            }
        }
    }
    else {
        for(y=0; y<maxy; y++) {
            for(x=0; x<maxx; x++) {
                gBufBfr[y][x] = gBuf[y][x];
                gBufAttrBfr[y][x] = gBufAttr[y][x];
            }
        }
    }
}

void mrefresh()
{
    mrefresh_buffer();
}

int mgetmaxx()
{
    struct winsize ws;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);

    return ws.ws_col;
}




int mgetmaxy()
{
    struct winsize ws;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);

#if defined(__CYGWIN__)
    return ws.ws_row-1;
#else
    return ws.ws_row;
#endif
}

static int gKeyBuf[1024];
static int gKeyBufNum = 0;

int mkbuf_exist() 
{
    if(gKeyBufNum > 0) 
        return 1;
    else
        return 0;
}

static int mgetch_(int* meta, int block)
{
    int i, j;
    int specialkey_check;
    int result;
    char buf[128];
    char tmp[128];
    int n;
    int n2;
    fd_set mask;
    struct timeval tv;
    int on_the_way;
    int match;
    struct sKeyMap* item;
    double count;

static int y = 0;

    *meta = 0;


    if(gKeyBufNum > 0) {
        while(1) {
            on_the_way = 0;

            if(gKeyBuf[0] == 27) {
                for(i=0; i<gKeyMapNum; i++) {
                    item = gKeyMap + i;
                    match = 1;

                    for(j=1; j<gKeyBufNum; j++) {
                        if(gKeyBuf[j] != item->mKeys[j-1]) {
                            match = 0;
                            break;
                        }
                    }

                    if(gKeyBufNum-1 == item->mNum) {
                        match = 0;
                    }

                    if(match) {
                        on_the_way = 1;
                        break;
                    }
                }
            }


            for(i=0; i<gKeyMapNum; i++) {
                item = gKeyMap + i;
                match = 1;

                for(j=0; j<gKeyBufNum; j++) {
                    if(gKeyBuf[j] != item->mKeys[j]) {
                        match = 0;
                        break;
                    }
                }

                if(gKeyBufNum == item->mNum) {
                    match = 0;
                }

                if(match) {
                    on_the_way = 1;
                    break;
                }
            }

            if(on_the_way) {
                count = 0;
                while(count < gKeyEscapeWait) {
                    usleep(1);
                    count++;

                    fd_set mask;

                    FD_ZERO(&mask);
                    FD_SET(gMCTtyFd, &mask);

                    struct timeval tv;
                    tv.tv_sec = 0;
                    tv.tv_usec = 0;

                    select(gMCTtyFd + 1, &mask, NULL, NULL, &tv);

                    if(FD_ISSET(gMCTtyFd, &mask)) {
                        break;
                    }
                }


#if defined(__CYGWIN__)
                fd_set mask;

                FD_ZERO(&mask);
                FD_SET(gMCTtyFd, &mask);

                struct timeval tv;
                tv.tv_sec = 0;
                tv.tv_usec = 0;

                select(gMCTtyFd + 1, &mask, NULL, NULL, &tv);

                if(FD_ISSET(gMCTtyFd, &mask)) {
                    if((n2 = ttyread(tmp, 10)) < 0) {
                        /*
                        perror("read1");
                        mexit(1);
                        */
                        return -1;
                    }
                }
                else {
                    n2 = 0;
                }
#else
                if((n2 = ttyread(tmp, 10)) < 0) {
                    /*
                    perror("read2");
                    mexit(1);
                    */
                    return -1;
                }
#endif

                if(n2 != 0)
                    for(i=0; i<n2; i++) gKeyBuf[gKeyBufNum++] = tmp[i];
                else
                    break;
            }
            else
                break;
        }

/*
mmvprintw(y, 10, "gKeyBufNum %d", gKeyBufNum);
for(i=0; i<gKeyBufNum; i++) {
mmvprintw(y,i*5+25, "(%d)", gKeyBuf[i]);
}
y++;
*/


        if(gKeyBuf[0] == 27) {
            for(i=0; i<gKeyMapNum; i++) {
                item = gKeyMap + i;

                specialkey_check = 1;

                if(gKeyBufNum-1 < item->mNum) {
                    specialkey_check = 0;
                }
                else {
                    for(j=0; j<item->mNum; j++) {
                        if(item->mKeys[j] != gKeyBuf[j+1]) {
                            specialkey_check = 0;
                            break;
                        }
                    }
                }

                if(specialkey_check) {
                    memmove(gKeyBuf, gKeyBuf + item->mNum+1,
                            sizeof(int)*(gKeyBufNum-item->mNum-1));
                    gKeyBufNum-=(item->mNum+1);
                    *meta = 1;
                    return item->mKey;
                }
            }
        }


        for(i=0; i<gKeyMapNum; i++) {
            item = gKeyMap + i;

            specialkey_check = 1;

            if(gKeyBufNum < item->mNum) {
                specialkey_check = 0;
            }
            else {
                for(j=0; j<item->mNum; j++) {
                    if(item->mKeys[j] != gKeyBuf[j]) {
                        specialkey_check = 0;
                        break;
                    }
                }
            }

            if(specialkey_check) {
                memmove(gKeyBuf, gKeyBuf + item->mNum,
                             sizeof(int)*(gKeyBufNum-item->mNum));
                gKeyBufNum-=item->mNum;
                return item->mKey;
            }
        }

        if(gKeyBuf[0] == 27 && gKeyBufNum > 1) {
            result = gKeyBuf[1];
            memmove(gKeyBuf, gKeyBuf + 2, sizeof(int)*(gKeyBufNum-2));
            gKeyBufNum-=2;

            *meta = 1;
            return result;
        }
        else {
            if(gKeyBufNum == 1) {
                gKeyBufNum--;
                return gKeyBuf[0];
            }
            else {
                result = gKeyBuf[0];
                memmove(gKeyBuf, gKeyBuf + 1, sizeof(int)*(gKeyBufNum-1));
                gKeyBufNum--;
                return result;
            }
        }
    }
    else {
        while(1) {
            n = 0;

            if(block) {
                while(n == 0) {
#if defined(__CYGWIN__)
                    fd_set mask;

                    FD_ZERO(&mask);
                    FD_SET(gMCTtyFd, &mask);

                    struct timeval tv;
                    tv.tv_sec = 0;
                    tv.tv_usec = 0;

                    select(gMCTtyFd+1, &mask, NULL, NULL, &tv);

                    if(FD_ISSET(gMCTtyFd, &mask)) {
                        if((n = ttyread(buf, 10)) < 0) {
switch(errno) {
case EIO:
puts("EIO");
break;

case EAGAIN:
puts("EAGAIN");
break;

case EBADF:
puts("EBADF");
break;

case EFAULT:
puts("EFAULT");
break;

case EINTR:
puts("EINTR");
break;

case EINVAL:
puts("EINVAL");
break;

case EISDIR:
puts("EISDIR");
break;
}
                            perror("read3");
                            exit(1);
                        }
                    }
                    else {
                        n = 0;
                    }
#else
                    fd_set mask;

                    FD_ZERO(&mask);
                    FD_SET(gMCTtyFd, &mask);

                    select(gMCTtyFd+1, &mask, NULL, NULL, NULL);

                    if(FD_ISSET(gMCTtyFd, &mask)) {
                        if((n = ttyread(buf, 10)) < 0) {
switch(errno) {
case EIO:
puts("EIO");
break;

case EAGAIN:
puts("EAGAIN");
break;

case EBADF:
puts("EBADF");
break;

case EFAULT:
puts("EFAULT");
break;

case EINTR:
puts("EINTR");
break;

case EINVAL:
puts("EINVAL");
break;

case EISDIR:
puts("EISDIR");
break;
}
                            perror("read4");
                            exit(1);
                        }
                    }

#endif
                }
            }
            else {
#if defined(__CYGWIN__)
                fd_set mask;

                FD_ZERO(&mask);
                FD_SET(gMCTtyFd, &mask);

                struct timeval tv;
                tv.tv_sec = 0;
                tv.tv_usec = 0;

                select(gMCTtyFd+1, &mask, NULL, NULL, &tv);

                if(FD_ISSET(gMCTtyFd, &mask)) {
                    if((n = ttyread(buf, 10)) < 0) {
                        perror("read5");
                        exit(1);
                    }
                }
                else {
                    n = 0;
                }
#else
                if((n = ttyread(buf, 10)) < 0) {
                    perror("read6");
                    exit(1);
                }
#endif
                if(n == 0) {
                    *meta = 0;
                    return -1;
                }
            }

            while(1) {
                /// escape key //
                if(buf[0] == 27 && n == 1) {
                    count = 0;
                    while(count < 10) {
                        /*
                        struct timespec t;
                        t.tv_sec = 0;
                        t.tv_nsec = 1000000;

                        nanosleep(&t, NULL);
                        count++;
                        */

                        usleep(1);
                        count++;

                        fd_set mask;

                        FD_ZERO(&mask);
                        FD_SET(gMCTtyFd, &mask);

                        struct timeval tv;
                        tv.tv_sec = 0;
                        tv.tv_usec = 0;

                        select(gMCTtyFd + 1, &mask, NULL, NULL, &tv);

                        if(FD_ISSET(gMCTtyFd, &mask)) {
                            count = -1;
                            break;
                        }
                    }

                    if(count != -1) {
                        break;
                    }
                    else {
#if defined(__CYGWIN__)
                        fd_set mask;

                        FD_ZERO(&mask);
                        FD_SET(gMCTtyFd, &mask);

                        struct timeval tv;
                        tv.tv_sec = 0;
                        tv.tv_usec = 0;

                        select(gMCTtyFd + 1, &mask, NULL, NULL, &tv);

                        if(FD_ISSET(gMCTtyFd, &mask)) {
                            if((n2 = ttyread(tmp, 10)) < 0) {
                                perror("read7-2");
                                exit(1);
                            }
                        }
                        else {
                            n2 = 0;
                        }
#else
                        if((n2 = ttyread(tmp, 10)) < 0) {
                            perror("read8-2");
                            exit(1);
                        }
#endif

                        if(n2 != 0)
                            for(i=0; i<n2; i++) buf[n++] = tmp[i];
                        else {
                            break;
                        }
                    }
                }
                /// not espace key ///
                else {
                    on_the_way = 0;

                    if(buf[0] == 27) {
                        for(i=0; i<gKeyMapNum; i++) {
                            item = gKeyMap + i;

                            match = 1;

                            for(j=1; j<n; j++) {
                                if(buf[j] != item->mKeys[j-1]) {
                                    match = 0;
                                    break;
                                }
                            }

                            if(n-1 == item->mNum) {
                                match = 0;
                            }

                            if(match) {
                                on_the_way = 1;
                                break;
                            }
                        }
                    }

                    for(i=0; i<gKeyMapNum; i++) {
                        item = gKeyMap + i;
                        match = 1;

                        for(j=0; j<n; j++) {
                            if(buf[j] != item->mKeys[j]) {
                                match = 0;
                                break;
                            }
                        }

                        if(n == item->mNum) {
                            match = 0;
                        }

                        if(match) {
                            on_the_way = 1;
                            break;
                        }
                    }

                    if(on_the_way) {
                        count = 0;
                        while(count < gKeyEscapeWait) {
                            usleep(1);
                            count++;

                            fd_set mask;

                            FD_ZERO(&mask);
                            FD_SET(gMCTtyFd, &mask);

                            struct timeval tv;
                            tv.tv_sec = 0;
                            tv.tv_usec = 0;

                            select(gMCTtyFd + 1, &mask, NULL, NULL, &tv);

                            if(FD_ISSET(gMCTtyFd, &mask)) {
                                break;
                            }
                        }


    #if defined(__CYGWIN__)
                        fd_set mask;

                        FD_ZERO(&mask);
                        FD_SET(gMCTtyFd, &mask);

                        struct timeval tv;
                        tv.tv_sec = 0;
                        tv.tv_usec = 0;

                        select(gMCTtyFd + 1, &mask, NULL, NULL, &tv);

                        if(FD_ISSET(gMCTtyFd, &mask)) {
                            if((n2 = ttyread(tmp, 10)) < 0) {
                                perror("read7");
                                exit(1);
                            }
                        }
                        else {
                            n2 = 0;
                        }
    #else

                        if((n2 = ttyread(tmp, 10)) < 0) {
                            perror("read8");
                            exit(1);
                        }
    #endif

                        if(n2 != 0)
                            for(i=0; i<n2; i++) buf[n++] = tmp[i];
                        else
                            break;

                    }
                    else
                        break;
                }
            }

/*
mmvprintw(y, 10, "read1 n %d", n);
for(i=0; i<n; i++) {
mmvprintw(y, i*5 + 25, "(%d)", buf[i]);
}
mrefresh();
y++;
*/

            if(buf[0] == 27 && n == 1) {
//puts("YYYY");
                *meta = 0;
                return 27;
            }
            if(buf[0] == 27) {
                for(i=0; i<gKeyMapNum; i++) {
                    item = gKeyMap + i; 
                    specialkey_check = 1;

                    if(n-1 < item->mNum) {
                         specialkey_check = 0;
                    }
                    else {
                        for(j=0; j<item->mNum; j++) {
                            if(item->mKeys[j] != buf[j+1]) {
                                specialkey_check = 0;
                                break;
                            }
                        }
                    }

                    if(specialkey_check) {
                        if(n-1 > item->mNum) {
                            for(j=item->mNum+1; j<n; j++) {
                                gKeyBuf[gKeyBufNum++] = buf[j];
                            }
                        }

                        *meta = 1;
                        return item->mKey;
                    }
                }
            }

            for(i=0; i<gKeyMapNum; i++) {
                item = gKeyMap + i;
                specialkey_check = 1;

                if(n < item->mNum) {
                    specialkey_check = 0;
                }
                else {
                    for(j=0; j<item->mNum; j++) {
                        if(item->mKeys[j] != buf[j]) {
                            specialkey_check = 0;
                            break;
                        }
                    }
                }

                if(specialkey_check) {
                    if(n > item->mNum) {
                        for(j=item->mNum; j<n; j++) {
                            gKeyBuf[gKeyBufNum++] = buf[j];
                        }
                    }

                    return item->mKey;
                }
            }


            if(buf[0] == 27 && n>1) {
                for(i=2; i<n; i++) {
                    gKeyBuf[gKeyBufNum++] = buf[i];
                }

                *meta = 1;
                return buf[1];
            }
            else {
                for(i=1; i<n; i++) {
                    gKeyBuf[gKeyBufNum++] = buf[i];
                }

                return buf[0];
            }
        }
    }
}
/*
{
    int n;
    char buf[128];
    fd_set mask;
    struct timeval tv;
    struct sKeyMap* keymap;
    int count;
    int i;
    int j;

    /// special keys ? ///
    if(gKeyRingHead < gKeyRingTail) {
        for(i=0; i<gKeyMapNum; i++) {
            keymap = gKeyMap + i;

            if(gKeyRingTail - gKeyRingHead >= keymap->mNum) {
                if(memcmp(gKeyRingHead, keymap->mKeys, keymap->mNum) == 0) {
                    gKeyRingHead += keymap->mNum;

                    if(gKeyRingHead == gKeyRingTail) {
                        gKeyRingHead = gKeyRing;
                        gKeyRingTail = gKeyRing;
                    }

                    return keymap->mKey;
                }
            }
        }
    }

    /// read if it can do ///
    count = 0;
    while(1) {
        FD_ZERO(&mask);
        FD_SET(gMCTtyFd, &mask);

        tv.tv_sec = 0;
        tv.tv_usec = 0;

        usleep(1);

        if(select(gMCTtyFd+1, &mask, NULL, NULL, &tv) < 0) {
            perror("select in mgetch");
            exit(1);
        }

        if(FD_ISSET(gMCTtyFd, &mask)) {
            if((n = ttyread(buf, 10)) < 0) {
                perror("read in mgetch_2");
                exit(1);
            }

            for(i=0; i<n; i++) {
                *gKeyRingTail++ = buf[i];
            }

            /// special keys ///
            for(i=0; i<gKeyMapNum; i++) {
                keymap = gKeyMap + i;

                if(gKeyRingTail - gKeyRingHead >= keymap->mNum) {
                    if(memcmp(gKeyRingHead, keymap->mKeys, keymap->mNum) == 0) {
                        gKeyRingHead += keymap->mNum;

                        if(gKeyRingHead == gKeyRingTail) {
                            gKeyRingHead = gKeyRing;
                            gKeyRingTail = gKeyRing;
                        }

                        return keymap->mKey;
                    }
                }
            }

            /// it's not special key
            char c = *gKeyRingHead++;

            if(gKeyRingHead == gKeyRingTail) {
                gKeyRingHead = gKeyRing;
                gKeyRingTail = gKeyRing;
            }

            return (int)c;
        }
    }
}
*/

int mgetch(int* meta)
{
    return mgetch_(meta, 1);
}

int mgetch_nonblock(int* meta)
{
    return mgetch_(meta, 0);
}

void mreset_tty()
{
    struct termios t;

    t.c_cc[VINTR] =  3;
    t.c_cc[VQUIT] =  28;
    t.c_cc[VERASE] =  127;
    t.c_cc[VKILL] =  21;
    t.c_cc[VEOF] =  4;
    t.c_cc[VTIME] =  0;
    t.c_cc[VMIN] =  1;
#if defined(VSWTC)
    t.c_cc[VSWTC] =  0;
#endif
    t.c_cc[VSTART] =  17;
    t.c_cc[VSTOP] =  19;
    t.c_cc[VSUSP] =  26;
    t.c_cc[VEOL] =  0;
    t.c_cc[VREPRINT] =  18;
    t.c_cc[VDISCARD] =  15;
    t.c_cc[VWERASE] =  23;
    t.c_cc[VLNEXT] =  22;
    t.c_cc[VEOL2] =  0;

    t.c_iflag = BRKINT | IGNPAR | ICRNL | IXON | IMAXBEL;
    t.c_oflag = OPOST | ONLCR;
    t.c_cflag = CREAD | CS8 | B38400;
    t.c_lflag = ISIG | ICANON 
                | ECHO | ECHOE | ECHOK 
                //| ECHOKE 
                //| ECHOCTL | ECHOKE 
                | IEXTEN;

    tcsetattr(STDIN_FILENO, TCSANOW, &t);
    //system("tset");
}

int mis_raw_mode()
{
    struct termios tty;
    tcgetattr(STDIN_FILENO, &tty);
    
    if((tty.c_lflag & ICANON) == ICANON) {
        return 0;
    }
    else {
        return 1;
    }
}

void msave_screen()
{
#if defined(__CYGWIN__)
    char buf[128];
    snprintf(buf, 128, "\033%d\033[?47h", 7);
    ttywrite(buf);
#else
    char* str = tigetstr("smcup");
    if(str) {
        ttywrite(str);
    }
#endif
}

void mrestore_screen()
{
#if defined(__CYGWIN__)
    char buf[128];
    snprintf(buf, 128, "\033[2J\033[?47l\033%d", 8);
    ttywrite(buf);
#else
    char* str = tigetstr("rmcup");
    if(str) {
        ttywrite(str);
    }
#endif
}



